﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using DevExpress.LookAndFeel;
using DevExpress.Skins;
using DevExpress.UserSkins;
using DevExpress.Utils;
using DevExpress.Utils.Drawing;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Docking;
using DevExpress.XtraEditors;
using DevExpress.XtraTabbedMdi;
using Moonlite.Compiling;
using Moonlite.Composition;
using Moonlite.Data.Configuration;
using Moonlite.Data.Configuration.Implementation;
using Moonlite.Data.Configuration.UI;
using Moonlite.Data.Mpq;
using Moonlite.ExtensionApi;
using Moonlite.ExtensionApi.ControlInterfaces;
using Moonlite.ExtensionApi.GlobalInterfaces;
using Moonlite.ExtensionApi.XimlInterfaces;
using Moonlite.Platform.General;
using Moonlite.Platform.Project;
using Moonlite.Platform.Text.File;
using Moonlite.Platform.Text.Project;
using Moonlite.Platform.Ximl;
using Moonlite.Services.CodeCompletion;
using Moonlite.UI.Shell.Controls;
using Moonlite.UI.Shell.Wizards;
using Storm.TextEditor.Editor.CodeCompletion;
using Storm.TextEditor.Editor.Exporters;
using Storm.TextEditor.Editor.Printing;
using Storm.TextEditor.Editor.Text;
using Storm.TextEditor.Parser.Objects;
namespace Moonlite
{
    [Export]
    public partial class Shell : XtraForm, IPartImportsSatisfiedNotification, IMoonliteShell
    {
        public event EventHandler StartTest;
        public event EventHandler StopTest;
        public event ProjectCreatedEventHandler ProjectCreated;
        public event ProjectEventHandler ProjectOpened;
        public event ProjectEventHandler ProjectClosed;
        public event FileEventHandler FileOpened;
        public event FileEventHandler FileSaved;
        public event FileEventHandler FileClosed;
        private List<Assembly> parsedAssemblies = new List<Assembly>();
        private List<Assembly> ParsedAssemblies
        {
            get { return parsedAssemblies; }
        }

        private bool loaded;
        private static AssemblyConfigurationAttachment attachment;
        public static AssemblyConfigurationAttachment Attachment
        {
            get { return attachment; }
        }
        private Dictionary<Type, List<object>> services = new Dictionary<Type, List<object>>();
        private List<Assembly> extensionAssemblies = new List<Assembly>();
        private const string CommentString = "//";
        private bool ReadOnly { get; set; }
        public List<Assembly> ExtensionAssemblies
        {
            get { return extensionAssemblies; }
        }
        public static Credits Credits { get; set; }
        private SplashScreen SplashScreen { get; set; }
        public StartPage StartPage { get; private set; }
        public CreateProjectWizard CreateProjectWizard { get; private set; }
        public CreateFileWizard CreateFileWizard { get; private set; }
        public ExtensionManagerForm ExtensionManagerForm { get; private set; }
        public TemplateManagerForm TemplateManagerForm { get; private set; }
        public CompilerOptionsForm CompilerOptionsForm { get; private set; }
        public ConfigurationForm ConfigurationForm { get; private set; }
        [ImportMany("Moonlite.Composition.WindowExtensionContract", AllowRecomposition = true)]
        public Lazy<UserControl, IWindowMetadata>[] Windows { get; set; }
        public static string Theme { get; set; }
        public static bool SaveProjectBeforeCompiling { get; set; }
        public static bool ShowSplashScreen { get; set; }
        public string ProgramStatus
        {
            get { return labelStatus.Caption; }
            set { labelStatus.Caption = value; }
        }

        public string ActiveSkinName
        {
            get { return defaultLookAndFeel.LookAndFeel.ActiveSkinName; }
        }

        private Hashtable InitializedHiddenPlugins { get; set; }
        public bool InterfaceHidden { get; private set; }
        private IProject project;
        public IProject Project
        {
            get { return project; }
            set
            {
                project = value;
                if (project != null)
                {
                    OpenProject();
                }
            }
        }

        public TextEditorCollection TextEditors
        {
            get
            {
                TextEditorCollection editors = new TextEditorCollection();
                foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
                {
                    if (page.MdiChild is ITextEditor)
                    {
                        editors.Add(page.MdiChild as ITextEditor);
                    }
                }
                return editors;
            }
        }

        public ProjectManager ProjectManager
        {
            get { return projectManager; }
        }

        public FunctionExplorer FunctionExplorer
        {
            get { return functionExplorer; }
        }

        public CodeExplorer CodeExplorer
        {
            get { return codeExplorer; }
            internal set { codeExplorer = value; }
        }

        public ErrorList ErrorList
        {
            get { return errorList; }
        }

        public ObjectBrowser ObjectBrowser
        {
            get { return objectBrowser; }
        }

        public Output Output
        {
            get { return output; }
        }

        public Moonlite.UI.Shell.Controls.Properties Properties
        {
            get { return properties; }
        }

        public BarManager BarManager
        {
            get { return barManager; }
        }

        public XtraTabbedMdiManager XtraTabbedMdiManager
        {
            get { return xtraTabbedMdiManager; }
        }

        public DockManager DockManager
        {
            get { return dockManager; }
        }

        public Bar StatusBar
        {
            get { return statusBar; }
        }

        public new bool DesignMode
        {
            get { return base.DesignMode; }
        }

        protected virtual void OnStartTest(EventArgs e)
        {
            if (StartTest != null)
            {
                StartTest(this, e);
            }
        }

        protected virtual void OnStopTest(EventArgs e)
        {
            if (StopTest != null)
            {
                StopTest(this, e);
            }
        }

        protected virtual void OnProjectOpened(ProjectEventArgs e)
        {
            if (e.Project.Type == ProjectType.Galaxy)
            {
                dpnlMapExplorer.Visibility = DockVisibility.Visible;
                dpnlObjectBrowser.Visibility = DockVisibility.Hidden;
            }
            else if (e.Project.Type == ProjectType.Jass)
            {
                dpnlMapExplorer.Visibility = DockVisibility.Hidden;
                dpnlObjectBrowser.Visibility = DockVisibility.Visible;
            }

            if (ProjectOpened != null)
            {
                ProjectOpened(this, e);
            }
        }

        protected virtual void OnProjectClosed(ProjectEventArgs e)
        {
            if (ProjectClosed != null)
            {
                ProjectClosed(this, e);
            }
        }

        protected virtual void OnFileOpened(FileEventArgs e)
        {
            if (FileOpened != null)
            {
                FileOpened(this, e);
            }
        }

        protected virtual void OnFileSaved(FileEventArgs e)
        {
            if (FileSaved != null)
            {
                FileSaved(this, e);
            }
        }

        protected virtual void OnFileClosed(FileEventArgs e)
        {
            if (FileClosed != null)
            {
                FileClosed(this, e);
            }
        }

        public string[] GetAllSkinNames()
        {
            List<string> skinNames = new List<string>();
            foreach (SkinContainer container in SkinManager.Default.Skins)
            {
                skinNames.Add(container.SkinName);
            }

            return skinNames.ToArray();
        }

        public void SetSkin(string skinName)
        {
            defaultLookAndFeel.LookAndFeel.SetSkinStyle(skinName);
        }

        public void SaveAppSettings()
        {
            if (attachment != null)
            {
                ConfigurationManager.SaveConfigurationInstanceToConfigurationDocument(attachment.ConfigurationInstance, attachment.ConfigurationStoragePath, true);
            }
        }

        public void OpenMapScript(int selectedRow, bool readOnly)
        {
            if (Project != null)
            {
                using (TMPQArchive archive = new TMPQArchive(Project.GetMapPath()))
                {
                    string war3mapPath = Application.StartupPath + "\\Temp\\war3mapPath.j";
                    if (File.Exists(war3mapPath) == true)
                    {
                        File.Delete(war3mapPath);
                    }

                    archive.ExportFile("war3map.j", war3mapPath);
                    OpenFile(war3mapPath, new ProjectFile() { Path = "war3map.j", Name = "war3map.j" });
                    if (IsCurrentTabPageTextEditor() == true)
                    {
                        ITextEditor textEditor = GetCurrentTabPageTextEditor();
                        textEditor.InnerTextEditor.ReadOnly = readOnly;
                        if (selectedRow > -1)
                        {
                            textEditor.InnerTextEditor.Caret.Position.Y = selectedRow;
                            textEditor.InnerTextEditor.ActiveViewControl.CenterInView(selectedRow);
                            SelectLine(textEditor);
                        }
                    }
                }
            }
        }

        public void OpenCurrentMapScript(int selectedRow, bool readOnly)
        {
            if (Project != null)
            {
                string war3mapPath = Application.StartupPath + "\\logs\\currentmapscript.j";
                OpenFile(war3mapPath, new ProjectFile() { Path = "war3map.j", Name = "war3map.j" });
                if (IsCurrentTabPageTextEditor() == true)
                {
                    ITextEditor textEditor = GetCurrentTabPageTextEditor();
                    textEditor.InnerTextEditor.ReadOnly = readOnly;
                    if (selectedRow > -1)
                    {
                        textEditor.InnerTextEditor.Caret.Position.Y = selectedRow;
                        textEditor.InnerTextEditor.ActiveViewControl.CenterInView(selectedRow);
                        SelectLine(textEditor);
                    }
                }
            }
        }

        public void OpenDocument(string caption, Form documentForm)
        {
            CreateTabbedForm(documentForm, caption);
        }

        public void OnImportsSatisfied()
        {
            ReloadWindows();
        }

        public void ReloadWindows()
        {
            OnLoad(this, EventArgs.Empty);
            foreach (var window in Windows.OrderBy(metaWindow => metaWindow.Metadata.DockId))
            {
                var childWindow = window.Value;
                RegisterService(childWindow, childWindow.GetType());
                List<DockPanel> removeDockPanels = new List<DockPanel>();
                foreach (DockPanel panel in dockManager.Panels)
                {
                    if (panel.Text == window.Metadata.Name)
                    {
                        removeDockPanels.Add(panel);
                    }
                }

                removeDockPanels.ForEach(dockManager.RemovePanel);
                if (window.Metadata.Hidden == true)
                {
                    if (InitializedHiddenPlugins.Contains(window.Metadata.Name) == false)
                    {
                        InitializedHiddenPlugins.Add(window.Metadata.Name, window);
                    }
                }

                if (window.Metadata.Hidden == false)
                {
                    childWindow.Dock = DockStyle.Fill;
                    DockingStyle dockStyle = DockingStyle.Float;
                    switch (window.Metadata.Dock)
                    {
                        case DockStyle.Top:
                            dockStyle = DockingStyle.Top;
                            break;
                        case DockStyle.Bottom:
                            dockStyle = DockingStyle.Bottom;
                            break;
                        case DockStyle.Left:
                            dockStyle = DockingStyle.Left;
                            break;
                        case DockStyle.Right:
                            dockStyle = DockingStyle.Right;
                            break;
                        case DockStyle.Fill:
                            Form form = new Form();
                            childWindow.Dock = DockStyle.Fill;
                            form.Controls.Add(childWindow);
                            form.Show();
                            CreateTabbedForm(form, window.Metadata.Name);
                            return;
                        case DockStyle.None:
                            break;
                    }

                    DockPanel dockPanel = dockManager.AddPanel(dockStyle);
                    dockPanel.Visibility = (window.Metadata.Flags & WindowFlags.NotVisible) == WindowFlags.NotVisible ? DockVisibility.Hidden : (window.Metadata.Flags & WindowFlags.AutoHide) == WindowFlags.AutoHide ? DockVisibility.AutoHide : DockVisibility.Visible;
                    dockPanel.ControlContainer.Controls.Add(childWindow);
                    dockPanel.Text = window.Metadata.Name;
                    if (window.Metadata.Icon != null)
                    {
                        ((ImageList)dockManager.Images).Images.Add(window.Metadata.Icon);
                        dockPanel.ImageIndex = ((ImageList)dockManager.Images).Images.Count - 1;
                    }
                    childWindow.Tag = dockPanel;
                    ExtensionAssemblies.Add(childWindow.GetType().Assembly);
                }

                Assembly extensionAssembly = childWindow.GetType().Assembly;
                if (ParsedAssemblies.Contains(extensionAssembly) != false)
                    continue;

                ParsedAssemblies.Add(extensionAssembly);
                foreach (string resourceName in extensionAssembly.GetManifestResourceNames())
                {
                    if (resourceName.EndsWith("." + Global.XimlFileExtension) != true)
                        continue;

                    Stream resourceStream = extensionAssembly.GetManifestResourceStream(resourceName);
                    using (StreamReader reader = new StreamReader(resourceStream))
                    {
                        XimlTree.Instance.BuildItem(reader.ReadToEnd(), false, extensionAssembly);
                    }
                }
            }
        }

        public void RemoveAllDockPanelsButBuiltIn()
        {
            List<DockPanel> removeDockPanels = new List<DockPanel>();
            foreach (DockPanel dockPanel in dockManager.Panels)
            {
                if (dockPanel != dpnlCodeExplorer && dockPanel != dpnlErrorList && dockPanel != dpnlFunctionExplorer
                    && dockPanel != dpnlProjectManager && dockPanel != dpnlProperties && dockPanel != dpnlOutput && dockPanel != dpnlCodeExplorer.ParentPanel &&
                    dockPanel != dpnlFunctionExplorer.ParentPanel && dockPanel != dpnlProjectManager.ParentPanel && dockPanel != dpnlMapExplorer && dockPanel != dpnlObjectBrowser)
                {
                    removeDockPanels.Add(dockPanel);
                }
            }

            removeDockPanels.ForEach(dockManager.RemovePanel);
        }

        public void FocusWindow(UserControl control)
        {
            foreach (var window in Windows.OrderBy(metaWindow => metaWindow.Metadata.DockId))
            {
                if (window.Value == control)
                {
                    DockPanel dockPanel = (DockPanel)control.Tag;
                    if (dockPanel != null)
                    {
                        dockPanel.Show();
                        break;
                    }
                }
            }
        }

        public void SaveAllFiles()
        {
            foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
            {
                Save(page);
            }
        }

        public void SaveProject(bool saveFiles, bool saveSettings)
        {
            if (Project == null) return;
            ProjectSerializer.SaveProject(Project);
            SaveProjectSettings(Project);
            if (saveFiles == true)
            {
                SaveAllFiles();
            }
        }

        public static void Save(XtraMdiTabPage page)
        {
            if (!(page.MdiChild is TextEditor))
                return;

            TextEditor textEditor = page.MdiChild as TextEditor;
            if (Path.GetFileName(textEditor.InnerTextEditor.FileName) == "currentmapscript.j")
                return;

            textEditor.InnerTextEditor.Save();
            textEditor.InnerTextEditor.Saved = true;
            if (textEditor.InnerTextEditor.ParseOnSave) textEditor.Open(textEditor.InnerTextEditor.FileName, textEditor.File);
            textEditor.UpdateFileName();
        }

        public void Save()
        {
            Save(xtraTabbedMdiManager.SelectedPage);
        }

        public void SaveAs(XtraMdiTabPage page)
        {
            if (page.MdiChild is TextEditor)
            {
                TextEditor textEditor = page.MdiChild as TextEditor;
                using (SaveFileDialog saveFileDialog = new SaveFileDialog { Filter = (Project.Type == ProjectType.Jass ? "Jass Code Files (*.jx)|*.jx" : "Galaxy Code Files (*.gx)|*.gx") + "|All Files (*.*)|*.*" })
                {
                    if (saveFileDialog.ShowDialog() != DialogResult.OK)
                    {
                        return;
                    }

                    textEditor.InnerTextEditor.Save(saveFileDialog.FileName);
                    if (textEditor.InnerTextEditor.ParseOnSave) textEditor.Open(textEditor.InnerTextEditor.FileName, textEditor.File);
                    textEditor.Update();
                    OnFileSaved(new FileEventArgs(textEditor, Project, textEditor.File, textEditor.InnerTextEditor.FileName));
                }
            }
        }

        public void SaveAs()
        {
            SaveAs(xtraTabbedMdiManager.SelectedPage);
        }

        private void OnSaveProjectItemClick(object sender, ItemClickEventArgs e)
        {
            SaveProject(true, true);
        }

        private XtraMdiTabPage CreateTabbedForm(Form form, string text)
        {
            form.Text = text;
            form.MdiParent = this;
            form.Show();
            return xtraTabbedMdiManager.SelectedPage;
        }

        public void OpenProject()
        {
            OpenProject(Project, false);
        }

        public void OpenProject(IProject project)
        {
            OpenProject(project, true);
        }

        public void OpenProject(IProject project, bool setProject)
        {
            RecentProjects.Projects.Add(project);
            StartPage.SaveRecentProjects();
            StartPage.LoadRecentProjects();
            if (setProject == true) Project = project;
            projectManager.OpenProject(project);
            LoadProjectSettings(project);
            UpdateEnabledItems(null, null);
            Text = project.Name + " - Moonlite Map Studio";
            AvailableProperties.ProjectName = project.Name.Replace(" ", "_");
            OnProjectOpened(new ProjectEventArgs(project));
            if (StartPage.ClosePageOnProjectLoad != true)
            {
                return;
            }

            StartPage.SavePageSettings();
            if (StartPage.ParentTabPage != null)
            {
                StartPage.ParentTabPage.MdiChild.Dispose();
            }
        }

        public IProject OpenProject(string filename, bool open)
        {
            if (!File.Exists(filename))
            {
                throw new IOException("File does not exist." + Environment.NewLine + filename);
            }

            IProject project = ProjectSerializer.LoadProject(filename);
            if (open)
            {
                OpenProject(project);
            }

            return project;
        }

        private void LoadProjectSettings(IProject project)
        {
            try
            {
                BinarySettingsService service = new BinarySettingsService(Path.GetDirectoryName(project.Path) + "\\" + project.Name + "." + Global.ProjectSettingsFileExtension);
                service.Read();
                foreach (ISettingsItem item in service.Items)
                {
                    if (item is SettingsCategory)
                    {
                        SettingsCategory openFilesCategory = (SettingsCategory)item;
                        if (openFilesCategory.Name == "files")
                        {
                            foreach (ISettingsItem categoryItem in openFilesCategory.Children)
                            {
                                ITextEditor textEditor = null;
                                foreach (ISettingsItem propertyItem in openFilesCategory.Children)
                                {
                                    if (propertyItem is SettingsCategory)
                                    {
                                        SettingsCategory category = (SettingsCategory)propertyItem;
                                        if (category.Name == "file")
                                        {
                                            foreach (ISettingsItem attributeItem in category.Children)
                                            {
                                                if (attributeItem is SettingsProperty)
                                                {
                                                    SettingsProperty property = (SettingsProperty)attributeItem;
                                                    if (property.Name == "path")
                                                    {
                                                        textEditor = OpenFile((string)property.Value, null);
                                                    }
                                                    else if (property.Name == "posX")
                                                    {
                                                        if (textEditor != null)
                                                        {
                                                            textEditor.InnerTextEditor.Caret.Position.X = (int)property.Value;
                                                            textEditor.InnerTextEditor.ActiveViewControl.ScrollIntoView();
                                                        }
                                                    }
                                                    else if (property.Name == "posY")
                                                    {
                                                        if (textEditor != null)
                                                        {
                                                            textEditor.InnerTextEditor.Caret.Position.Y = (int)property.Value;
                                                            textEditor.InnerTextEditor.ActiveViewControl.ScrollIntoView();
                                                        }
                                                    }
                                                }
                                                else if (attributeItem is SettingsCategory)
                                                {
                                                    SettingsCategory attributeCategory = (SettingsCategory)attributeItem;
                                                    if (attributeCategory.Name == "rowAttributes")
                                                    {
                                                        Row row = null;
                                                        foreach (ISettingsItem rowItem in attributeCategory.Children)
                                                        {
                                                            if (rowItem is SettingsProperty)
                                                            {
                                                                SettingsProperty rowProperty = (SettingsProperty)rowItem;
                                                                if (rowProperty.Name == "index")
                                                                {
                                                                    row = textEditor.InnerTextEditor.Document[(int)rowProperty.Value];
                                                                }
                                                                else if (rowProperty.Name == "bookmarked")
                                                                {
                                                                    if (row != null)
                                                                    {
                                                                        row.Bookmarked = (bool)rowProperty.Value;
                                                                    }
                                                                }
                                                                else if (rowProperty.Name == "breakpoint")
                                                                {
                                                                    if (row != null)
                                                                    {
                                                                        row.Breakpoint = (bool)rowProperty.Value;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Log += exception.Message + Environment.NewLine;
            }
        }

        private void SaveProjectSettings(IProject project)
        {
            try
            {
                BinarySettingsService service = new BinarySettingsService(Path.GetDirectoryName(project.Path) + "\\" + project.Name + "." + Global.ProjectSettingsFileExtension);
                SettingsCategory openFilesCategory = new SettingsCategory("files", new SettingsItemCollection());
                foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
                {
                    if (page.MdiChild is TextEditor)
                    {
                        TextEditor textEditor = (TextEditor)page.MdiChild;
                        textEditor.InnerTextEditor.Document.ParseAll(true);
                        SettingsCategory editorCategory = new SettingsCategory("file", new SettingsItemCollection());
                        SettingsProperty pathProperty = new SettingsProperty("path", textEditor.InnerTextEditor.FileName, null);
                        SettingsProperty scrollPosXProperty = new SettingsProperty("posX", textEditor.InnerTextEditor.Caret.OldLogicalXPos, null);
                        SettingsProperty scrollPosYProperty = new SettingsProperty("posY", textEditor.InnerTextEditor.Caret.Position.Y, null);
                        SettingsCategory rowAttributesCategory = new SettingsCategory("rowAttributes", new SettingsItemCollection());
                        foreach (Row row in textEditor.InnerTextEditor.Document)
                        {
                            SettingsProperty indexProperty = new SettingsProperty("index", row.Index, null);
                            SettingsProperty bookmarkedProperty = new SettingsProperty("bookmarked", row.Bookmarked, null);
                            SettingsProperty breakpointProperty = new SettingsProperty("breakpoint", row.Breakpoint, null);
                            rowAttributesCategory.Children.Add(indexProperty);
                            rowAttributesCategory.Children.Add(bookmarkedProperty);
                            rowAttributesCategory.Children.Add(breakpointProperty);
                        }
                        editorCategory.Children.Add(pathProperty);
                        editorCategory.Children.Add(scrollPosXProperty);
                        editorCategory.Children.Add(scrollPosYProperty);
                        editorCategory.Children.Add(rowAttributesCategory);
                        openFilesCategory.Children.Add(editorCategory);
                    }
                }
                service.Items.Add(openFilesCategory);
                service.Write();
            }
            catch (Exception exception)
            {
                Logger.Log += exception.Message + Environment.NewLine;
            }
        }

        public void LaunchOpenProjectDialog()
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "Jass Project Files (*.jxproj)|*.jxproj|Galaxy Project Files (*.gxproj)|*.gxproj|All Files(*.*)|*.*" })
            {
                openFileDialog.FilterIndex = 3;
                if (openFileDialog.ShowDialog() != DialogResult.OK)
                {
                    return;
                }

                CloseProject(true);
                Project = ProjectSerializer.LoadProject(openFileDialog.FileName);
                OpenProject(Project);
            }
        }

        public void CreateProject()
        {
            CreateProjectWizard.StartPosition = FormStartPosition.CenterParent;
            CreateProjectWizard.ShowDialog();
            if (CreateProjectWizard.Result == false)
            {
                return;
            }

            ProjectSerializer.SaveProject(CreateProjectWizard.Project);
            Project = CreateProjectWizard.Project;
            OpenProject(Project);
            UpdateEnabledItems(null, null);
            AvailableProperties.ProjectName = Project.Name.Replace(" ", "_");
            if (Project.Type == ProjectType.Galaxy) OnGalaxyProjectCreated(Project, CreateProjectWizard.Template);
            if (Project.Type == ProjectType.Jass) OnJassProjectCreated(Project, CreateProjectWizard.Template);
            if (StartPage.ClosePageOnProjectLoad != true)
            {
                return;
            }

            Text = "Moonlite Map Studio";
            StartPage.SavePageSettings();
            if (StartPage.ParentTabPage != null)
            {
                StartPage.ParentTabPage.MdiChild.Dispose();
            }
        }

        public virtual void OnProjectCreated(ProjectCreatedEventArgs e)
        {
            ProjectCreatedEventHandler handler = ProjectCreated;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void OnGalaxyProjectCreated(IProject project, IProjectTemplate template)
        {
            OnProjectCreated(new ProjectCreatedEventArgs(project, template));
            template.OnCreated(project);
        }

        private void OnJassProjectCreated(IProject project, IProjectTemplate template)
        {
            OnProjectCreated(new ProjectCreatedEventArgs(project, template));
            template.OnCreated(project);
        }

        public IProjectFile CreateFile(bool defaultFile)
        {
            CreateFileWizard.DefaultFile = defaultFile;
            CreateFileWizard.StartPosition = FormStartPosition.CenterParent;
            CreateFileWizard.ShowDialog();
            if (CreateFileWizard.Result == false)
            {
                return null;
            }

            UpdateEnabledItems(null, null);
            return CreateFileWizard.File;
        }

        public void RemoveTextEditor(ITextEditor editor)
        {
            XtraMdiTabPage removePage = null;
            foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
            {
                if (page.MdiChild == editor)
                {
                    removePage = page;
                    break;
                }
            }
            if (removePage != null)
            {
                xtraTabbedMdiManager.Pages.Remove(removePage);
            }
        }

        public IProjectFile CreateFile()
        {
            return CreateFile(false);
        }

        public ITextEditor OpenFile(string filePath)
        {
            return OpenFile(filePath, new ProjectFile() { Name = Path.GetFileName(filePath), Path = filePath, ReadOnly = false });
        }

        public ITextEditor OpenFile(string filePath, IProjectFile file)
        {
            DirectoryHelper.CreatePath(filePath);
            if (File.Exists(filePath) == false)
            {
                ShowError("File doesn't exist.");
                return null;
            }

            foreach (XtraMdiTabPage tabPage in xtraTabbedMdiManager.Pages)
            {
                if ((tabPage.MdiChild is TextEditor) == false)
                {
                    continue;
                }

                TextEditor pageTextEditor = tabPage.MdiChild as TextEditor;
                if (pageTextEditor.InnerTextEditor.FileName != filePath)
                {
                    continue;
                }

                xtraTabbedMdiManager.SelectedPage = tabPage;
                return pageTextEditor;
            }

            TextEditor textEditor = new TextEditor() { Text = Path.GetFileName(filePath) };
            textEditor.InnerTextEditor.ReadOnly = ReadOnly;
            textEditor.ParentPage = CreateTabbedForm(textEditor, textEditor.Text);
            textEditor.Open(filePath, file);
            textEditor.InnerTextEditor.ReadOnly = file.ReadOnly;
            textEditor.Show();
            UpdateEnabledItems(null, null);
            UpdateZoomSliderToMatch(true);
            OnFileOpened(new FileEventArgs(textEditor, Project, file, filePath));
            return textEditor;
        }

        public bool CloseFile(ITextEditor editor, bool prompt, bool removePage)
        {
            foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
            {
                if (page.MdiChild == editor)
                {
                    return CloseFile(page, prompt, removePage);
                }
            }
            return false;
        }

        public bool CloseFile(XtraMdiTabPage page, bool prompt, bool removePage)
        {
            if (CompilerManager.IsJassHelperRunning() == true)
            {
                CompilerManager.CurrentJassHelperProcess.WaitForExit();
            }

            if (page == null)
            {
                return false;
            }

            if (prompt == true && IsEditorFileSaved(page) == false)
            {
                ITextEditor textEditor = page.MdiChild as ITextEditor;
                DialogResult dialogResult = XtraMessageBox.Show(String.Format("Save unsaved changes to {0}?",
                    Path.GetFileName(textEditor.InnerTextEditor.FileName)), "Moonlite Map Studio",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

                if (dialogResult == DialogResult.Yes)
                {
                    textEditor.InnerTextEditor.Save();
                    textEditor.Close();
                    OnFileClosed(new FileEventArgs(textEditor, Project, textEditor.File, textEditor.InnerTextEditor.FileName));
                }
                else if (dialogResult == DialogResult.Cancel)
                {
                    return false;
                }
            }

            UpdateEnabledItems(false, true);
            SaveProjectSettings(Project);
            if (removePage == false)
                return true;

            page.MdiChild.Close();
            UpdateEnabledItems(false, true);
            return true;
        }

        public void CloseDocument(Form documentForm)
        {
            documentForm.Close();
        }

        public bool CloseFile(bool prompt, bool removePage)
        {
            return CloseFile(xtraTabbedMdiManager.SelectedPage, prompt, removePage);
        }

        public bool CloseProject(bool prompt)
        {
            if (CompilerManager.IsJassHelperRunning() == true)
            {
                CompilerManager.CurrentJassHelperProcess.WaitForExit();
            }

            if (prompt == true && Project != null && IsProjectSaved(true) == false)
            {
                if (IsProjectSaved(true) == false)
                {
                    DialogResult dialogResult = XtraMessageBox.Show(String.Format("Save unsaved changes to {0}?",
                        Project.Name), "Moonlite Map Studio", MessageBoxButtons.YesNoCancel,
                        MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

                    if (dialogResult == DialogResult.Yes)
                    {
                        SaveProject(false, true);
                    }
                    else if (dialogResult == DialogResult.Cancel)
                    {
                        return false;
                    }
                }

                TextEditorCollection editors = new TextEditorCollection();
                foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
                {
                    if (page.MdiChild is TextEditor) editors.Add(page.MdiChild as TextEditor);
                }

                foreach (TextEditor textEditor in editors)
                {
                    textEditor.Close();
                }

                bool cancel = xtraTabbedMdiManager.Pages.Count > 0;
                if (cancel == true)
                {
                    return false;
                }
            }

            SaveProjectSettings(Project);
            OnProjectClosed(new ProjectEventArgs(Project));
            Project = null;
            xtraTabbedMdiManager.Pages.Clear();
            projectManager.CloseProject();
            FunctionExplorer.Clear();
            CodeExplorer.Clear();
            UpdateEnabledItems(null, null);
            if (StartPage.ClosePageOnProjectLoad == false)
            {
                return true;
            }

            StartPage = new StartPage();
            StartPage.LoadPageSettings();
            StartPage.ParentTabPage = CreateTabbedForm(StartPage, "Start Page");
            StartPage.Show();
            Text = "Start Page - Moonlite Map Studio";
            return true;
        }

        public static bool IsEditorFileSaved(XtraMdiTabPage editorPage)
        {
            if (editorPage == null) return true;
            if (editorPage.MdiChild is TextEditor)
            {
                TextEditor textEditor = editorPage.MdiChild as TextEditor;
                return textEditor.Saved;
            }
            else
            {
                return true;
            }
        }

        public bool IsEditorFileSaved()
        {
            return IsEditorFileSaved(xtraTabbedMdiManager.SelectedPage);
        }

        public bool IsProjectSaved(bool includeFiles)
        {
            if (Project == null)
                return true;

            bool projectSaved = false;
            IProject projectAtFile = ProjectSerializer.LoadProject(Project.Path);
            projectSaved = Project.Compare(projectAtFile);
            if (projectSaved == true && includeFiles == true)
            {
                foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
                {
                    bool fileSaved = IsEditorFileSaved(page);
                    if (fileSaved != false)
                        continue;

                    projectSaved = false;
                    break;
                }
            }

            return projectSaved;
        }

        private void OnLoad(object sender, EventArgs e)
        {
            if (!loaded)
            {
                BonusSkins.Register();
                OfficeSkins.Register();
                DirectoryHelper.CreateFolderPath(Global.GetAppDataSettingsFolder());
                defaultLookAndFeel.LookAndFeel.SetSkinStyle(Theme);
                loaded = true;
            }
        }

        private void OnFormClosing(object sender, FormClosingEventArgs e)
        {
            if (Project != null && CloseProject(true) == false)
            {
                e.Cancel = true;
                return;
            }

            mapExplorer.Loaded();
            e.Cancel = false;
            SetInterfaceMode(false);
            DirectoryHelper.CreateFolderPath(Global.GetAppDataSettingsFolder());
            Theme = defaultLookAndFeel.LookAndFeel.ActiveSkinName;
        }

        private void OnNewFileItemClick(object sender, ItemClickEventArgs e)
        {
            if (Project != null)
            {
                CreateFile();
            }
        }

        private void OnSaveItemClick(object sender, ItemClickEventArgs e)
        {
            Save();
        }

        public bool IsCurrentTabPageTextEditor()
        {
            if (xtraTabbedMdiManager.Pages.Count == 0 || xtraTabbedMdiManager.SelectedPage == null)
            {
                return false;
            }

            return xtraTabbedMdiManager.SelectedPage.MdiChild is ITextEditor;
        }

        public ITextEditor GetCurrentTabPageTextEditor()
        {
            try
            {
                if (xtraTabbedMdiManager.SelectedPage == null)
                {
                    return null;
                }

                return xtraTabbedMdiManager.SelectedPage.MdiChild as ITextEditor;
            }
            catch (Exception exception)
            {
                Logger.Log += exception.Message;
            }
            return null;
        }

        public void UpdateEnabledItems(bool? textEditor, bool? project)
        {
            bool currentTextEditor = textEditor == null ? IsCurrentTabPageTextEditor() : textEditor == true;
            bool currentProject = project == null ? Project != null : project == true;
            btnSave.Enabled = currentTextEditor;
            btnPaste.Enabled = currentTextEditor;
            btnCut.Enabled = currentTextEditor;
            btnCopy.Enabled = currentTextEditor;
            btnUndo.Enabled = currentTextEditor;
            btnRedo.Enabled = currentTextEditor;
            findTextBox.Enabled = currentTextEditor;
            btnFind.Enabled = currentTextEditor;
            btnStartDebugging.Enabled = currentProject && !InterfaceHidden;
            btnStopDebugging.Enabled = currentProject && InterfaceHidden;
            btnRestartDebugging.Enabled = currentProject && InterfaceHidden;
            btnPrint.Enabled = currentTextEditor;
            btnExportAsHtml.Enabled = currentTextEditor;
            btnClose.Enabled = currentTextEditor;
            btnCloseProject.Enabled = currentProject;
            btnSaveAs.Enabled = currentTextEditor;
            btnDelete.Enabled = currentTextEditor;
            btnSelectAll.Enabled = currentTextEditor;
            btnFindAndReplace.Enabled = currentTextEditor;
            btnGoTo.Enabled = currentTextEditor;
            btnBookmarks.Enabled = currentTextEditor;
            btnBuildBinaryLibrary.Enabled = currentProject;
            btnBuildMapScript.Enabled = currentProject;
            btnAddNewItem.Enabled = currentProject;
            btnAddExistingItem.Enabled = currentProject;
            btnNewFolder.Enabled = currentProject;
            btnProperties.Enabled = currentProject;
            btnNormalView.Enabled = currentTextEditor;
            btnTwoViews.Enabled = currentTextEditor;
            btnFourViews.Enabled = currentTextEditor;
            btnSaveAll.Enabled = currentProject;
            btnNewDocument.Enabled = currentProject;
            UpdateToolbars(currentTextEditor, currentProject);
            if (zoomSlider.Enabled != currentTextEditor)
            {
                UpdateZoomSliderToMatch(currentTextEditor);
            }
        }

        public void UpdateZoomSliderToMatch(bool currentTextEditor)
        {
            if (currentTextEditor)
            {
                zoomSlider.Enabled = true;
                zoomLevel.Enabled = true;
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                int value = ((int)textEditor.InnerTextEditor.FontSize == 0 ? 10 : (int)textEditor.InnerTextEditor.FontSize) * 10;
                zoomSlider.EditValue = value;
                zoomLevel.EditValue = value.ToString() + "%";
            }
            else
            {
                zoomSlider.Enabled = false;
                zoomLevel.Enabled = false;
            }
        }

        public void SetZoomSliderToMatch()
        {
            if (IsCurrentTabPageTextEditor())
            {
                float fontSize = ((int)zoomSlider.EditValue) / 10f;
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                textEditor.InnerTextEditor.FontSize = fontSize;
                zoomLevel.EditValue = ((int)zoomSlider.EditValue).ToString() + "%";
            }
        }

        public void UpdateToolbars(bool currentTextEditor, bool currentProject)
        {
            textEditorToolbar.Visible = currentTextEditor;
        }

        private void OnXtraTabbedMdiManagerSelectedPageChanged(object sender, EventArgs e)
        {
            UpdateEnabledItems(null, null);
            if (IsCurrentTabPageTextEditor() != true)
            {
                return;
            }

            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            if (textEditor != null && textEditor.InnerTextEditor != null && textEditor.InnerTextEditor.FileName != "")
            {
                ObjectBrowser.Parser = JassInheritanceManager.GetParserFromFile(textEditor.InnerTextEditor.FileName);
            }
        }

        public static void SelectLine(ITextEditor textEditor)
        {
            textEditor.InnerTextEditor.Caret.SetPosition(new TextPoint(0, textEditor.InnerTextEditor.Caret.Position.Y));
            textEditor.InnerTextEditor.Caret.CropPosition();
            textEditor.InnerTextEditor.Selection.SelStart = textEditor.InnerTextEditor.Caret.Offset;
            textEditor.InnerTextEditor.Selection.SelLength = textEditor.InnerTextEditor.Caret.CurrentRow.Text.Length;
        }

        private static void DeleteLine(ITextEditor textEditor)
        {
            SelectLine(textEditor);
            textEditor.InnerTextEditor.Selection.Text = "";
        }

        private static void DeleteAll(ITextEditor textEditor)
        {
            textEditor.InnerTextEditor.SelectAll();
            textEditor.InnerTextEditor.Selection.Text = "";
        }

        private void OnPasteItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.Paste();
        }

        private void OnCutItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.Cut();
        }

        private void OnCopyItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.Copy();
        }

        private void OnDeleteItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.Delete();
        }

        private void OnDeleteLineItemClick(object sender, ItemClickEventArgs e)
        {
            DeleteLine(GetCurrentTabPageTextEditor());
        }

        private void OnDeleteAllItemClick(object sender, ItemClickEventArgs e)
        {
            DeleteAll(GetCurrentTabPageTextEditor());
        }

        private void OnUndoItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.Undo();
        }

        private void OnRedoItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.Redo();
        }

        private void OnToggleBookmarkItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.ToggleBookmark();
        }

        private void OnPreviousBookmarkItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.GotoPreviousBookmark();
        }

        private void OnNextBookmarkItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.GotoNextBookmark();
        }

        private void OnDisplayWordCompletionItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.CodeCompletionWindow.Show();
        }

        private void OnDisplayQuickInfoItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() == true)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                textEditor.InnerTextEditor.CodeCompletionWindow.ShowTooltipForSelectedItem();
            }
        }

        private void OnFindItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.ShowFind();
        }

        private void OnFindNextItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.FindNext();
        }

        private void OnReplaceItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.ShowReplace();
        }

        private void OnSelectLineItemClick(object sender, ItemClickEventArgs e)
        {
            SelectLine(GetCurrentTabPageTextEditor());
        }

        private void OnSelectAllItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.SelectAll();
        }

        private void OnGoToItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.ShowGotoLine();
        }

        private void OnShowOptionsWindow(object sender, ItemClickEventArgs e)
        {
            ConfigurationForm.ShowDialog();
        }

        private void OnShowCompilerOptionsItemClick(object sender, ItemClickEventArgs e)
        {
            CompilerOptionsForm.ShowDialog();
        }

        private void OnCompileMapScriptItemClick(object sender, ItemClickEventArgs e)
        {
            ProgramStatus = "Building";
            if (SaveProjectBeforeCompiling == true)
            {
                SaveProject(true, true);
            }

            if (Project.Type == ProjectType.Jass) CompilerManager.ExecuteWc3();
            if (Project.Type == ProjectType.Galaxy) CompilerManager.ExecuteAndromeda();
            ProgramStatus = "Ready";
        }

        private void OnCloseProjectItemClick(object sender, ItemClickEventArgs e)
        {
            CloseProject(true);
        }

        private void OnCloseItemClick(object sender, ItemClickEventArgs e)
        {
            CloseFile(true, true);
        }

        private void OnNewProjectItemClick(object sender, ItemClickEventArgs e)
        {
            CreateProject();
        }

        private void OnSaveAsItemClick(object sender, ItemClickEventArgs e)
        {
            SaveAs();
        }

        private void OnOpenProjectItemClick(object sender, ItemClickEventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "Jass Project Files (*.jxproj)|*.jxproj|Galaxy Project Files (*.gxproj)|*.gxproj|All Files (*.*)|*.*" })
            {
                openFileDialog.FilterIndex = 3;
                if (openFileDialog.ShowDialog() != DialogResult.OK)
                {
                    return;
                }

                CloseProject(true);
                OpenProject(ProjectSerializer.LoadProject(openFileDialog.FileName));
                xtraTabbedMdiManager.Pages.Clear();
            }
        }

        private void OnOpenFileItemClick(object sender, ItemClickEventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "Jass Code Files (*.jx)|*.jx|Galaxy Code Files (*.gx)|*.gx|Jass Project Files (*.jxproj)|*.jxproj|Galaxy Project Files (*.gxproj)|*.gxproj|All Files (*.*)|*.*" })
            {
                openFileDialog.FilterIndex = 5;
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    if (Global.IsFileValidProject(openFileDialog.FileName))
                    {
                        OpenProject(ProjectSerializer.LoadProject(openFileDialog.FileName), true);
                    }
                    else
                    {
                        OpenFile(openFileDialog.FileName, new ProjectFile() { Path = Path.GetDirectoryName(openFileDialog.FileName), Name = Path.GetFileName(openFileDialog.FileName) });
                    }
                }
            }
        }

        private void OnExportAsHtmlItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() == true)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                using (SaveFileDialog saveFileDialog = new SaveFileDialog { Filter = "Html Web Pages (*.html;*.htm)|*.html;*.htm" })
                {
                    if (saveFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        HtmlExporter exporter = new HtmlExporter();
                        using (StreamWriter writer = File.CreateText(saveFileDialog.FileName))
                        {
                            writer.Write(exporter.Export(textEditor.InnerTextEditor.Document, ""));
                        }
                    }
                }
            }
        }

        private void OnPrintItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() == true)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                using (CodePrintDocument printDocument = new CodePrintDocument(textEditor.InnerTextEditor.Document))
                {
                    using (PrintDialog printDialog = new PrintDialog { Document = printDocument })
                    {
                        if (printDialog.ShowDialog() == DialogResult.OK)
                        {
                            printDialog.Document.Print();
                        }
                    }
                }
            }
        }

        private void OnShowExtensionManagerItemClick(object sender, ItemClickEventArgs e)
        {
            ExtensionManagerForm = new ExtensionManagerForm();
            ExtensionManagerForm.ShowDialog();
        }

        private void OnDockManagerLayoutUpgrade(object sender, LayoutUpgadeEventArgs e)
        {
            ReloadWindows();
        }

        public void SetOpenTextEditorsReadOnly(bool readOnly)
        {
            ReadOnly = readOnly;
            foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
            {
                if (page.MdiChild is TextEditor)
                {
                    TextEditor textEditor = page.MdiChild as TextEditor;
                    textEditor.InnerTextEditor.ReadOnly = readOnly;
                }
            }
        }

        public void SetInterfaceMode(bool hidden)
        {
            string settingsPath = Global.GetAppDataSettingsFolder() + "\\" + Global.DockLayoutFileName;
            if (hidden == true)
            {
                dockManager.SaveLayoutToXml(settingsPath);
            }

            if (hidden == true)
            {
                try
                {
                    dpnlProjectManager.Visibility = dpnlProjectManager.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlProperties.Visibility = dpnlProperties.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlFunctionExplorer.Visibility = dpnlFunctionExplorer.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlCodeExplorer.Visibility = dpnlCodeExplorer.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlErrorList.Visibility = dpnlErrorList.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlOutput.Visibility = dpnlOutput.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlObjectBrowser.Visibility = dpnlObjectBrowser.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                    dpnlMapExplorer.Visibility = dpnlMapExplorer.Visibility == DockVisibility.Visible ? DockVisibility.AutoHide : DockVisibility.Hidden;
                }
                catch (InvalidOperationException exception)
                {
                    Logger.Log += exception.Message + Environment.NewLine;
                }
            }
            else if (File.Exists(settingsPath) == true)
            {
                dockManager.RestoreLayoutFromXml(settingsPath);
            }

            btnStopDebugging.Enabled = hidden;
            btnRestartDebugging.Enabled = hidden;
            btnStartDebugging.Enabled = hidden == false;
            InterfaceHidden = hidden;
        }

        private void OnGameProcessExit(object sender, EventArgs e)
        {
            StopProjectTest();
        }

        private void StartProjectTest()
        {
            ProgramStatus = "Starting debugging";
            if (SaveProjectBeforeCompiling == true)
            {
                SaveProject(true, true);
            }

            if (GameManager.Instance.StartGame(Project, true))
            {
                SetOpenTextEditorsReadOnly(true);
                SetInterfaceMode(true);
                OnStartTest(EventArgs.Empty);
            }

            ProgramStatus = "Ready";
        }

        private void StopProjectTest()
        {
            ProgramStatus = "Stopping debugging";
            GameManager.Instance.StopGame();
            SetOpenTextEditorsReadOnly(false);
            SetInterfaceMode(false);
            OnStopTest(EventArgs.Empty);
            ProgramStatus = "Ready";
        }

        private void RestartProjectTest()
        {
            StopProjectTest();
            StartProjectTest();
        }

        private void OnTestMapItemClick(object sender, ItemClickEventArgs e)
        {
            StartProjectTest();
        }

        private void OnStopTestingItemClick(object sender, ItemClickEventArgs e)
        {
            StopProjectTest();
        }

        private void OnRestartTestItemClick(object sender, ItemClickEventArgs e)
        {
            RestartProjectTest();
        }

        private void OnAddEmptyFileItemClick(object sender, ItemClickEventArgs e)
        {
            if (Project != null)
            {
                projectManager.CreateNewFile(true);
            }
        }

        private void OnAddFileFromTemplateItemClick(object sender, ItemClickEventArgs e)
        {
            if (Project != null)
            {
                projectManager.CreateNewFile();
            }
        }

        private void OnAddFolderItemClick(object sender, ItemClickEventArgs e)
        {
            if (Project != null)
            {
                projectManager.AddFolder();
            }
        }

        private void OnNormalViewItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() == true)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                textEditor.InnerTextEditor.ResetSplitview();
            }
        }

        private void OnTwoViewsItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() == true)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                textEditor.InnerTextEditor.ResetSplitview();
                textEditor.InnerTextEditor.SplitVerticalHalf();
            }
        }

        private void OnFourViewsItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() == true)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                textEditor.InnerTextEditor.ResetSplitview();
                textEditor.InnerTextEditor.SplitHorizontalHalf();
                textEditor.InnerTextEditor.SplitVerticalHalf();
            }
        }

        private void OnRunBugReporterItemClick(object sender, ItemClickEventArgs e)
        {
            if (File.Exists(Application.StartupPath + "\\bugreporter.exe") == true)
            {
                Process.Start(Application.StartupPath + "\\bugreporter.exe");
            }
            else
            {
                ShowError("Cannot find Moonlite Bug Reporting Service executable. Please check your installation.");
            }
        }

        public static void ShowError(string message)
        {
            XtraMessageBox.Show(message, "Moonlite Map Studio", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
        }

        private void OnShowPluginWindowsItemClick(object sender, ItemClickEventArgs e)
        {
            ReloadWindows();
        }

        private void OnProjectManagerItemClick(object sender, ItemClickEventArgs e)
        {
            if (dpnlProjectManager.Visibility == DockVisibility.Hidden)
            {
                dpnlProjectManager.Visibility = DockVisibility.Visible;
            }
        }

        private void OnFunctionExplorerItemClick(object sender, ItemClickEventArgs e)
        {
            if (dpnlFunctionExplorer.Visibility == DockVisibility.Hidden)
            {
                dpnlFunctionExplorer.Visibility = DockVisibility.Visible;
            }
        }

        private void OnCodeExplorerItemClick(object sender, ItemClickEventArgs e)
        {
            if (dpnlCodeExplorer.Visibility == DockVisibility.Hidden)
            {
                dpnlCodeExplorer.Visibility = DockVisibility.Visible;
            }
        }

        private void OnErrorListItemClick(object sender, ItemClickEventArgs e)
        {
            if (dpnlErrorList.Visibility == DockVisibility.Hidden)
            {
                dpnlErrorList.Visibility = DockVisibility.Visible;
            }
        }

        private void OnObjectBrowserItemClick(object sender, ItemClickEventArgs e)
        {
            if (dpnlObjectBrowser.Visibility == DockVisibility.Hidden)
            {
                dpnlObjectBrowser.Visibility = DockVisibility.Visible;
            }
        }

        private void OnPropertiesItemClick(object sender, ItemClickEventArgs e)
        {
            if (dpnlProperties.Visibility == DockVisibility.Hidden)
            {
                dpnlProperties.Visibility = DockVisibility.Visible;
            }
        }

        private void OnIndentItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() != true)
            {
                return;
            }

            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            if (textEditor.InnerTextEditor.Selection.IsValid == false)
            {
                char indentationCharacter = textEditor.InnerTextEditor.KeepTabs == true ? '\t' : ' ';
                int currentCaretX = textEditor.InnerTextEditor.Caret.Position.X;
                textEditor.InnerTextEditor.Caret.Position.X = 0;
                if (textEditor.InnerTextEditor.KeepTabs == true)
                {
                    textEditor.InnerTextEditor.ActiveViewControl.InsertText(indentationCharacter.ToString());
                }
                else
                {
                    string indentation = new string(indentationCharacter, textEditor.InnerTextEditor.TabSpaces);
                    textEditor.InnerTextEditor.ActiveViewControl.InsertText(indentation);
                }

                textEditor.InnerTextEditor.Caret.Position.X = currentCaretX + textEditor.InnerTextEditor.TabSpaces;
            }
            else
            {
                textEditor.InnerTextEditor.Selection.Indent();
            }
        }

        private void OnOutdentItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() != true)
            {
                return;
            }

            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            if (textEditor.InnerTextEditor.Selection.IsValid == false)
            {
                Row currentRow = textEditor.InnerTextEditor.Caret.CurrentRow;
                char indentationCharacter = textEditor.InnerTextEditor.KeepTabs == true ? '\t' : ' ';
                int indentationLength = currentRow.Text.Length - currentRow.Text.TrimStart(indentationCharacter).Length;
                int currentCaretX = textEditor.InnerTextEditor.Caret.Position.X;
                indentationLength = Math.Min(indentationLength, textEditor.InnerTextEditor.TabSpaces);
                textEditor.InnerTextEditor.Caret.Position.X = indentationLength;
                if (textEditor.InnerTextEditor.KeepTabs == true)
                {
                    textEditor.InnerTextEditor.Caret.MoveLeft(false);
                    textEditor.InnerTextEditor.Delete();
                }
                else if (indentationLength >= textEditor.InnerTextEditor.TabSpaces)
                {
                    TextRange indentationRange = new TextRange
                    {
                        FirstColumn = textEditor.InnerTextEditor.Caret.Position.X - indentationLength,
                        FirstRow = currentRow.Index,
                        LastColumn = textEditor.InnerTextEditor.Caret.Position.X,
                        LastRow = currentRow.Index
                    };

                    textEditor.InnerTextEditor.Document.DeleteRange(indentationRange);
                }

                textEditor.InnerTextEditor.Caret.Position.X = Math.Max(currentCaretX - indentationLength, 0);
            }
            else
            {
                textEditor.InnerTextEditor.Selection.Outdent();
            }
        }

        private void OnAboutItemClick(object sender, ItemClickEventArgs e)
        {
            Credits.ShowDialog();
        }

        private void OnShowTemplateManagerItemClick(object sender, ItemClickEventArgs e)
        {
            TemplateManagerForm = new TemplateManagerForm();
            TemplateManagerForm.ShowDialog();
        }

        private void OnStartPageItemClick(object sender, ItemClickEventArgs e)
        {
            bool containsStartPage = false;
            foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
            {
                if ((page.Text == "Start Page" && page.MdiChild is StartPage) == false)
                {
                    continue;
                }

                xtraTabbedMdiManager.SelectedPage = page;
                containsStartPage = true;
                break;
            }

            if (containsStartPage == true)
            {
                return;
            }

            StartPage = new StartPage();
            StartPage.LoadPageSettings();
            StartPage.ParentTabPage = CreateTabbedForm(StartPage, "Start Page");
            StartPage.Show();
        }

        public void ViewProjectProperties()
        {
            foreach (XtraMdiTabPage page in xtraTabbedMdiManager.Pages)
            {
                if (!(page.MdiChild is ProjectProperties))
                    continue;

                xtraTabbedMdiManager.SelectedPage = page;
                return;
            }

            ProjectProperties projectProperties = new ProjectProperties { Project = Project };
            CreateTabbedForm(projectProperties, "Properties");
        }

        private void OnBuildLibraryItemClick(object sender, ItemClickEventArgs e)
        {
            labelStatus.Caption = "Building binary library...";
            LibraryManager.Instance.BuildLibrary(Project);
            labelStatus.Caption = "Ready";
        }

        private void SearchCurrentDocument(string text)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            if (textEditor != null && !string.IsNullOrEmpty(text))
            {
                textEditor.InnerTextEditor.ActiveViewControl.SelectNext(text, false, false, false);
            }
        }

        private void OnFindTextBoxEditValueChanged(object sender, EventArgs e)
        {
            SearchCurrentDocument((string)findTextBox.EditValue);
        }

        private void OnLocalFindItemClick(object sender, ItemClickEventArgs e)
        {
            SearchCurrentDocument((string)findTextBox.EditValue);
        }

        private void OnExitItemClick(object sender, ItemClickEventArgs e)
        {
            Close();
        }

        private void OnClearBookmarksItemClick(object sender, ItemClickEventArgs e)
        {
            DialogResult dialogResult = XtraMessageBox.Show("Are you sure you want to delete all of your bookmark(s)?", "Moonlite Map Studio", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
            if (dialogResult == DialogResult.Yes)
            {
                ITextEditor textEditor = GetCurrentTabPageTextEditor();
                if (textEditor != null)
                {
                    foreach (Row row in textEditor.InnerTextEditor.Document)
                    {
                        if (row.Bookmarked) row.Bookmarked = false;
                    }
                }

                textEditor.InnerTextEditor.Invalidate();
            }
        }

        private void OnRecentProjectItemClick(object sender, ItemClickEventArgs e)
        {
            Project project = e.Item.Tag as Project;
            if (project != null)
            {
                OpenProject(project, true);
            }
        }

        public void UpdateRecentProjects()
        {
            PopupMenu popupMenu = new PopupMenu();
            btnRecentProjects.DropDownControl = popupMenu;
            foreach (Project recentProject in RecentProjects.Projects)
            {
                BarButtonItem item = new BarButtonItem(barManager, recentProject.Name);
                item.ItemClick += OnRecentProjectItemClick;
                item.Tag = recentProject;
                popupMenu.AddItem(item);
            }
        }

        private void OnAddExistingItemClick(object sender, ItemClickEventArgs e)
        {
            if (Project == null) return;
            string extension = String.Format(".{0}", (Project.Type == ProjectType.Galaxy ? Global.GalaxyFileExtension : Global.JassFileExtension));
            using (OpenFileDialog addExistingItemDialog = new OpenFileDialog { Filter = "All Files (*.*)|*.*" })
            {
                if (addExistingItemDialog.ShowDialog() == DialogResult.OK)
                {
                    projectManager.AddExistingFile(addExistingItemDialog.FileName);
                }
            }
        }

        private void OnCommentItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() != true)
            {
                return;
            }

            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            if (textEditor.InnerTextEditor.Selection.IsValid == false)
            {
                int currentCaretX = textEditor.InnerTextEditor.Caret.Position.X;
                textEditor.InnerTextEditor.Caret.Position.X = 0;
                textEditor.InnerTextEditor.ActiveViewControl.InsertText(CommentString);
                textEditor.InnerTextEditor.Caret.Position.X = currentCaretX + CommentString.Length;
            }
            else
            {
                textEditor.InnerTextEditor.Selection.Indent(CommentString);
            }
        }

        private void OnUncommentItemClick(object sender, ItemClickEventArgs e)
        {
            if (IsCurrentTabPageTextEditor() != true)
            {
                return;
            }

            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            if (textEditor.InnerTextEditor.Selection.IsValid == false)
            {
                Row currentRow = textEditor.InnerTextEditor.Caret.CurrentRow;
                int length = currentRow.Text.Length - currentRow.Text.TrimStart(CommentString.ToCharArray()).Length;
                int currentCaretX = textEditor.InnerTextEditor.Caret.Position.X;
                length = Math.Min(length, textEditor.InnerTextEditor.TabSpaces);
                textEditor.InnerTextEditor.Caret.Position.X = length;
                if (length >= CommentString.Length)
                {
                    TextRange indentationRange = new TextRange
                    {
                        FirstColumn = textEditor.InnerTextEditor.Caret.Position.X - length,
                        FirstRow = currentRow.Index,
                        LastColumn = textEditor.InnerTextEditor.Caret.Position.X,
                        LastRow = currentRow.Index
                    };

                    textEditor.InnerTextEditor.Document.DeleteRange(indentationRange);
                }

                textEditor.InnerTextEditor.Caret.Position.X = Math.Max(currentCaretX - length, 0);
            }
            else
            {
                textEditor.InnerTextEditor.Selection.Outdent(CommentString);
            }
        }

        public void AddDescriptors()
        {
            BarDescriptor mainMenuDescriptor = new BarDescriptor(new XimlNode(), null, NativeElementGuids.MainMenuBarGuid) { Name = mainMenu.Text, Tag = mainMenu };
            BarDescriptor defaultBarDescriptor = new BarDescriptor(new XimlNode(), null, NativeElementGuids.DefaultBarGuid) { Name = toolbar.Text, Tag = toolbar };
            BarDescriptor textEditorBarDescriptor = new BarDescriptor(new XimlNode(), null, NativeElementGuids.TextEditorBarGuid) { Name = textEditorToolbar.Text, Tag = textEditorToolbar };
            BarDescriptor statusBarDescriptor = new BarDescriptor(new XimlNode(), null, NativeElementGuids.StatusBarGuid) { Name = statusBar.Text, Tag = statusBar };
            BarItemDescriptor fileButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.FileButtonGuid) { Text = btnFile.Caption, Tag = btnFile };
            BarItemDescriptor editButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.EditButtonGuid) { Text = btnEdit.Caption, Tag = btnEdit };
            BarItemDescriptor viewButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.ViewButtonGuid) { Text = btnView.Caption, Tag = btnView };
            BarItemDescriptor projectButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.ProjectButtonGuid) { Text = btnProject.Caption, Tag = btnProject };
            BarItemDescriptor buildButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.BuildButtonGuid) { Text = btnBuild.Caption, Tag = btnBuild };
            BarItemDescriptor toolsButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.ToolsButtonGuid) { Text = btnTools.Caption, Tag = btnTools };
            BarItemDescriptor helpButtonDescriptor = new BarItemDescriptor(new XimlNode(), null, NativeElementGuids.HelpButtonGuid) { Text = btnHelp.Caption, Tag = btnHelp };
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.MainMenuBarGuid, mainMenuDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.DefaultBarGuid, defaultBarDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.TextEditorBarGuid, textEditorBarDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.StatusBarGuid, statusBarDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.FileButtonGuid, fileButtonDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.EditButtonGuid, editButtonDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.ViewButtonGuid, viewButtonDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.ProjectButtonGuid, projectButtonDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.BuildButtonGuid, buildButtonDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.ToolsButtonGuid, toolsButtonDescriptor);
            XimlTree.Instance.Descriptors.Add(NativeElementGuids.HelpButtonGuid, helpButtonDescriptor);
        }

        public new object GetService(Type serviceType)
        {
            if (services.ContainsKey(serviceType))
            {
                return services[serviceType].ToArray();
            }

            return null;
        }

        public void RegisterService(object service, Type serviceType)
        {
            if (DesignMode)
            {
                return;
            }

            List<object> existingServices = null;
            if (services.ContainsKey(serviceType))
            {
                existingServices = services[serviceType];
            }

            if (existingServices == null)
            {
                services[serviceType] = new List<object>() { service };
            }
            else
            {
                existingServices.Add(service);
            }
        }

        private void OnFindPreviousItemClick(object sender, ItemClickEventArgs e)
        {
            ITextEditor textEditor = GetCurrentTabPageTextEditor();
            textEditor.InnerTextEditor.FindPrevious();
        }

        private void OnProjectPropertiesItemClick(object sender, ItemClickEventArgs e)
        {
            ViewProjectProperties();
        }

        private void OnZoomSliderEditValueChanged(object sender, EventArgs e)
        {
            SetZoomSliderToMatch();
        }

        private void OnZoomSliderRepositoryItemEditValueChanged(object sender, EventArgs e)
        {
            barManager.ActiveEditItemLink.PostEditor();
        }

        private void OnZoomLevelEditValueChanged(object sender, EventArgs e)
        {
            string value = zoomLevel.EditValue as string;
            if (value.EndsWith("%"))
            {
                value = value.TrimEnd('%');
            }

            bool allNumbers = true;
            foreach (char c in value)
            {
                if (!char.IsDigit(c))
                {
                    allNumbers = false;
                    break;
                }
            }

            if (!allNumbers)
            {
                value = "100";
            }

            int result;
            if (!int.TryParse(value, out result))
            {
                value = "100";
            }

            result = Math.Min(result, 400);
            result = Math.Max(result, 50);
            zoomSlider.EditValue = result;
            SetZoomSliderToMatch();
        }

        private void OnToggleCompletionModeDownChanged(object sender, ItemClickEventArgs e)
        {
            ITextEditor currentTextEditor = GetCurrentTabPageTextEditor();
            if (currentTextEditor != null)
            {
                if (btnToggleCompletionMode.Down)
                {
                    currentTextEditor.InnerTextEditor.CodeCompletionWindow.Mode = CodeCompletionMode.Suggestion;
                }
                else
                {
                    currentTextEditor.InnerTextEditor.CodeCompletionWindow.Mode = CodeCompletionMode.Standard;
                }
            }
        }

        public Shell()
        {
            Global.Instance = this;
            SplashScreen = new SplashScreen();
            attachment = new AssemblyConfigurationAttachment(Assembly.GetExecutingAssembly(), typeof(MoonliteConfigurationInstance));
            ConfigurationManager.LoadAssemblyConfigurationAttachment(attachment);
            ExtensionManagerForm = new ExtensionManagerForm();
            ConfigurationForm = new ConfigurationForm();
            if (ShowSplashScreen)
            {
                SplashScreen.Show();
            }
            DynamicSyntaxCheckingScheduler.Enabled = !DesignMode;
            InitializeComponent();
            barManager.ForceInitialize();
            RegisterService(this, GetType().GetInterface("IProjectEventManager"));
            RegisterService(barManager, typeof(BarManager));
            CreateFileWizard = new CreateFileWizard();
            CreateProjectWizard = new CreateProjectWizard();
            InitializedHiddenPlugins = new Hashtable();
            GameManager.Instance.GameProcessExit += OnGameProcessExit;
            DirectoryHelper.CreateFolderPath(Application.LocalUserAppDataPath + "\\Settings");
            RegistrySettings.Initialize();
            xtraTabbedMdiManager.MdiParent = this;
            output.AddStream(AndromedaOutputStream.Instance);
            Credits = new Credits();
            FunctionExplorer.ReadNativeCode();
            FunctionExplorer.OpenConnection();
            CompilerOptionsForm = new CompilerOptionsForm();
            StartPage = new StartPage();
            StartPage.LoadPageSettings();
            StartPage.ParentTabPage = CreateTabbedForm(StartPage, "Start Page");
            xtraTabbedMdiManager.Float(StartPage.ParentTabPage, new System.Drawing.Point(0, 0));
            UpdateEnabledItems(null, null);
            AddDescriptors();
            Timer itemsTimer = new Timer();
            itemsTimer.Interval = 500;
            itemsTimer.Tick += (object sender, EventArgs e) =>
            {
                UpdateEnabledItems(IsCurrentTabPageTextEditor(), Project != null);
            };
            itemsTimer.Start();
            if (StartPage.ShowPageOnStartup == false)
            {
                SplashScreen.Hide();
                return;
            }

            StartPage.Show();
            Text = "Start Page - Moonlite Map Studio";
            SplashScreen.Hide();
        }
    }
}